/**
 * @author
 * Júlio Zynger
 * DRE: 110092466
 */
package view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

import model.AFD;
import model.Estado;
import controller.Brzozowski;
import controller.simboloForaDoAlfabetoException;

@SuppressWarnings("serial")
public class TabelaTransicoes extends JFrame {
	private JPanel contentPane;
	private JTable table;
	private JLabel lblPalavra;
	private JTextField tfPalavra;
	private ArrayList<String> alf;
	private LinkedHashMap<String, Estado> estados, finais;
	private Estado inicial;
	private int funcao;

	public TabelaTransicoes(ArrayList<String> alf, LinkedHashMap<String, Estado> estados, LinkedHashMap<String, Estado> finais, Estado inicial, int funcao) {
		this.funcao = funcao;
		this.alf = alf;
		this.estados = estados;
		this.finais = finais;
		this.inicial = inicial;
		
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		GridLayout gl_contentPane = new GridLayout(2, 0);
		contentPane.setLayout(gl_contentPane);
		setResizable(false);
		setTitle("Transições");
		setContentPane(contentPane);
		
		String[] columnNames = new String[alf.size()+1];
		columnNames[0] = "Estado";
		for (int i = 0; i < alf.size(); i++) {
			columnNames[i+1] = alf.get(i);
		}
		
		String[][] data = new String[this.estados.values().size()][this.alf.size()+1];
		
		table = new JTable(data, columnNames){
			@Override
			public boolean isCellEditable(int row, int column) {
				if(column == 0) return false;
				else return super.isCellEditable(row, column);
			};
		};
		table.getTableHeader().setReorderingAllowed(false);
		table.setFont(new Font("Tahoma", Font.PLAIN, 10));
		table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
		
		JPanel palavra = new JPanel();
		FlowLayout fl_palavra = new FlowLayout(FlowLayout.CENTER);
		fl_palavra.setHgap(10);
		fl_palavra.setVgap(10);
		palavra.setLayout(fl_palavra);
		contentPane.add(palavra);
		
		lblPalavra = new JLabel("Palavra:");
		lblPalavra.setHorizontalTextPosition(SwingConstants.CENTER);
		lblPalavra.setHorizontalAlignment(SwingConstants.LEFT);
		palavra.add(lblPalavra, BorderLayout.WEST);
		
		tfPalavra = new JTextField();
		tfPalavra.setHorizontalAlignment(SwingConstants.CENTER);
		palavra.add(tfPalavra, BorderLayout.CENTER);
		tfPalavra.setColumns(20);
		
		JButton btnIr = new JButton("Computar Palavra");
		palavra.add(btnIr, BorderLayout.EAST);
		
		setUpStateColumn(table);
		
		for (int i = 1; i < table.getColumnModel().getColumnCount(); i++) {
			setUpComboboxColumn(table, table.getColumnModel().getColumn(i)); //TODO nao posso deixar que entre com celulas vazias
		}
		
		ActionListener aceitarPalavra = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				String palavra = tfPalavra.getText();
				
				for (Estado e : TabelaTransicoes.this.estados.values()) {
					LinkedHashMap<String, Estado> transic = new LinkedHashMap<String, Estado>();
					
					int j = 0;					
					while(!e.getNome().equals(table.getValueAt(j, 0))){
						j++;
					}
					
					for (int i = 1; i < table.getColumnCount(); i++) {
						transic.put((String) table.getColumnModel().getColumn(i).getHeaderValue(), TabelaTransicoes.this.estados.get(table.getValueAt(j, i)));
					}
					
					e.setTransicoes(transic);
				}
				
				AFD automato = new AFD(TabelaTransicoes.this.alf, TabelaTransicoes.this.estados,
						TabelaTransicoes.this.inicial, TabelaTransicoes.this.finais);
				
				boolean aceito = false, erroSimb = false;
				Dialog d;
				try {
					aceito = automato.computar(palavra);
				} catch (simboloForaDoAlfabetoException e2) {
					d = new Dialog(e2.getMessage());
					d.setTitle("Símbolo fora do alfabeto");
					erroSimb = true;
				}
				
				if(!erroSimb){
					Estado ondeParei = automato.getParei();
					
					
					if(aceito){
						d = new Dialog("Palavra aceita", automato.getSeqEst(), automato.getSeqConf(), ondeParei);
						d.setTitle("Aceito");
					}
					else{
						d = new Dialog("Palavra rejeitada", automato.getSeqEst(), automato.getSeqConf(), ondeParei);
						d.setTitle("Rejeitado");
					}
				}
			}
		};
		
		if(this.funcao==1 || this.funcao==2){
			tfPalavra.setVisible(false);
			lblPalavra.setVisible(false);
			btnIr.setText("Executar Algoritmo");
		}
		
		ActionListener brzozowski = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				for (Estado es : TabelaTransicoes.this.estados.values()) {
					LinkedHashMap<String, Estado> transic = new LinkedHashMap<String, Estado>();
					
					int j = 0;					
					while(!es.getNome().equals(table.getValueAt(j, 0))){
						j++;
					}
					
					for (int i = 1; i < table.getColumnCount(); i++) {
						transic.put((String) table.getColumnModel().getColumn(i).getHeaderValue(), TabelaTransicoes.this.estados.get(table.getValueAt(j, i)));
					}
					
					es.setTransicoes(transic);
				}
				
				AFD automato = new AFD(TabelaTransicoes.this.alf, TabelaTransicoes.this.estados,
						TabelaTransicoes.this.inicial, TabelaTransicoes.this.finais);
				
				String expressao = "";
				expressao = new Brzozowski(automato).brzozowski();
				
				Dialog d = new Dialog(expressao);
				d.setTitle("Expressão Regular");
			}
		};
		
		ActionListener kleene = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				for (Estado es : TabelaTransicoes.this.estados.values()) {
					LinkedHashMap<String, Estado> transic = new LinkedHashMap<String, Estado>();
					
					int j = 0;					
					while(!es.getNome().equals(table.getValueAt(j, 0))){
						j++;
					}
					
					for (int i = 1; i < table.getColumnCount(); i++) {
						transic.put((String) table.getColumnModel().getColumn(i).getHeaderValue(), TabelaTransicoes.this.estados.get(table.getValueAt(j, i)));
					}
					
					es.setTransicoes(transic);
				}
				
				AFD automato = new AFD(TabelaTransicoes.this.alf, TabelaTransicoes.this.estados,
						TabelaTransicoes.this.inicial, TabelaTransicoes.this.finais);
				
				String expressao = "";
				expressao = automato.kleene();
				
				Dialog d = new Dialog(expressao);
				d.setTitle("Expressão Regular");
			}
		};
		
		if(this.funcao == 0) btnIr.addActionListener(aceitarPalavra);
		if(this.funcao == 1) btnIr.addActionListener(brzozowski);
		if(this.funcao == 2) btnIr.addActionListener(kleene);
		
		this.setVisible(true);
	}
	
	public void setUpComboboxColumn(JTable table, TableColumn Column) {
		//Seta os valores contidos no combobox
		JComboBox comboBox = new JComboBox();
		for (Estado e : estados.values()) {
			comboBox.addItem(e.getNome());
		}
		Column.setCellEditor(new DefaultCellEditor(comboBox));
		
		DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
		renderer.setToolTipText("Clique para alterar o estado");
		Column.setCellRenderer(renderer);
	}
	
	public void setUpStateColumn(JTable table) {
		int i=0;
		for (Estado e : this.estados.values()) {
			table.setValueAt(e.getNome(), i, 0);
			i++;
		}
	}

	public void imprimeDados(boolean erroInicial, boolean erroFinais){
		System.out.println("Símbolos do Alfabeto:");
		for (String s : alf) {
			System.out.println(s);
		}
		System.out.println();
		
		System.out.println("Estados:");
		for (Iterator<Estado> it = estados.values().iterator(); it.hasNext();) {
			Estado e = (Estado) it.next();
			System.out.println(e.getNome());
		}
		System.out.println();
		
		if(!erroInicial){
			System.out.println("Estado inicial:");
			System.out.println(inicial.getNome());
		}
		
		if(!erroFinais){
			System.out.println("Estados Finais:");
			for (Iterator<Estado> it = finais.values().iterator(); it.hasNext();) {
				Estado e = (Estado) it.next();
				System.out.println(e.getNome());
			}
		}
	}
	
}
